package mirrormonkey.util.netevent.client;

import mirrormonkey.util.netevent.client.ClientEventManager;
import mirrormonkey.util.netevent.client.ClientStateEventCreator;
import mirrormonkey.util.netevent.client.tools.MockClient;
import mirrormonkey.util.netevent.client.tools.MockClientStateListener;

import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;

import com.jme3.network.Client;
import com.jme3.network.ClientStateListener;
import com.jme3.network.ClientStateListener.DisconnectInfo;

/**
 * Integration test: For the whole package <tt>mirrormonkey.util.netevent</tt>,
 * test if client state changes are processed and relayed correctly by the
 * framework.
 * 
 * @author Philipp Christian Loewner
 * 
 */
public class ClientStateEventTest {

	private static final MockClient[] NO_CLIENTS = {};

	private static final DisconnectInfo[] NO_INFO = {};

	private static MockClient[] clients;

	private static ClientEventManager manager;

	private static ClientStateEventCreator creator;

	private static MockClientStateListener[] listeners;

	@BeforeClass
	public static void setUpClass() {
		clients = new MockClient[] { new MockClient(), new MockClient() };

		manager = new ClientEventManager();

		creator = manager.getClientStateListener();
		for (Client c : clients) {
			c.addClientStateListener(creator);
		}

		listeners = new MockClientStateListener[] {
				new MockClientStateListener(), new MockClientStateListener() };
	}

	@After
	public void tearDown() {
		MockClientStateListener.reset(listeners);
	}

	public void connectAll(Client[] clients) {
		for (Client c : clients) {
			creator.clientConnected(c);
		}
	}

	public void disconnectAll(Client[] clients, DisconnectInfo[] info) {
		for (int i = 0; i < clients.length; i++) {
			creator.clientDisconnected(clients[i], info[i]);
		}
	}

	public void checkEvents(Client[] connected, Client[] disconnected,
			DisconnectInfo[] info) {
		MockClientStateListener.checkConnected(listeners, connected);
		MockClientStateListener
				.checkDisconnected(listeners, disconnected, info);
	}

	/**
	 * Tests if cliendConnected calls are relayed correctly
	 */
	@Test
	public void testConnectEvent() {
		for (ClientStateListener l : listeners) {
			manager.addClientStateListener(l);
		}
		connectAll(clients);
		checkEvents(NO_CLIENTS, NO_CLIENTS, NO_INFO);

		manager.processEvents();
		checkEvents(clients, NO_CLIENTS, NO_INFO);
	}

	/**
	 * Tests if clientDisconnected calls are relayed correctly
	 */
	@Test
	public void testDisconnectEvent() {
		DisconnectInfo[] d = new DisconnectInfo[] { new DisconnectInfo(),
				new DisconnectInfo() };
		disconnectAll(clients, d);
		checkEvents(NO_CLIENTS, NO_CLIENTS, NO_INFO);

		manager.processEvents();
		checkEvents(NO_CLIENTS, clients, d);
	}

	/**
	 * Tests if removing listeners stops exactly their notification
	 */
	@Test
	public void testListenerRemove() {
		manager.removeClientStateListener(listeners[0]);
		creator.clientConnected(clients[0]);
		manager.processEvents();

		listeners[0].checkConnected(NO_CLIENTS);
		listeners[1].checkConnected(new Client[] { clients[0] });
	}

}
